package chapter_3.frame;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;


/**
 * 采用界定符的方式来实现消息的封装成帧以及消息帧的解析
 *
 * @author fulv
 */
public class DelimitFramer implements Framer {

    /**
     * 数据输入源，从中解析出消息帧
     */
    private InputStream in;

    /**
     * 消息帧的定界符
     */
    private static final byte DELIMITER = '@';
    /**
     * 替换字符，用于将出现在消息内部的'\n'进行替换，避免出现解析错误
     */
    private static final byte REPLACE_CHAR = (byte) 0x7d;

    private static final byte MASK = (byte) 0x20;

    //public DelimitFramer(){}
    public DelimitFramer(InputStream in) {
        this.in = in;
    }

    @Override
    public void frameMsg(byte[] msg, OutputStream out) {
        //向判断传入的消息中是否包含界定符与替换符，如果存在，执行相关字节填充操作
        //将对应的界定符和替换符换成两个字符，其中第一个为替换符，第二个为将要替换的字符的从左到右的第二位取反形成的字符
        int count = 0;
        for (byte b : msg) {
            if (DELIMITER == b || REPLACE_CHAR == b) {
                count++;
            }
        }
        byte[] extendMsg = new byte[msg.length + count];
        for (int i = 0, j = 0; i < msg.length; i++) {
            if (DELIMITER == msg[i] || REPLACE_CHAR == msg[i]) {
                extendMsg[j++] = REPLACE_CHAR;
                extendMsg[j++] = byteStuff(msg[i]);
            } else {
                extendMsg[j++] = msg[i];
            }
        }
        try {
            out.write(extendMsg);
            out.write(DELIMITER);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("消息写入流失败");
        }


    }

    /**
     * 从消息输入流in中，取出下一个消息帧（以分隔符划分一个消息帧）
     *
     * @return
     */
    @Override
    public byte[] nextMsg() throws IOException {
        ByteArrayOutputStream msgBuffer = new ByteArrayOutputStream();
        int nextByte;

        while ((nextByte = in.read()) != DELIMITER) {
            //已经读完了输入流，这里分两种情况
            if (-1 == nextByte) {
                //输入流中的字节已经全部读完
                if (msgBuffer.size() == 0) {
                    return null;
                } else {
                    //读取了部分字节，但却没有遇到分隔符，说明输入的消息帧是不完整或者错误的，返回异常
                    throw new EOFException("读取到了不正确的消息帧");
                }
            }

            //当前字符为替换字符，需要读取下一个字符并转换(将第三位取反)得到正确的字符
            if (REPLACE_CHAR == nextByte) {
                nextByte = in.read() & 0xFF;
                nextByte = byteStuff((byte) nextByte);
            }
            msgBuffer.write(nextByte);
        }
        return msgBuffer.toByteArray();
    }

    /**
     * 字节填充函数，将传入字节的从左到右数的第二位取反
     *
     * @param originByte
     * @return
     */
    private static byte byteStuff(byte originByte) {
        return (byte) ((originByte | MASK) & ~(originByte & MASK));
    }
}
